﻿#include "NetSnake.h"
#include "../MultiSnake/MultiSnake.h"
#include "qtimer.h"
#include <chrono>
#include <thread>

NetSnake::NetSnake(QWidget* parent, int cellNum, int cellLen) : MultiSnake(parent, cellNum, cellLen)
{
}

NetSnake::~NetSnake() {
};

void NetSnake::init() {
	initGame();
	initNetWrok();
	initCurrentPlayer();
	initOtherPlayers();
	generateFood();
	startGameLoop();
}

void NetSnake::initNetWrok() {
	this->client = new GameClient("127.0.0.1", 6000, [this](char* buffer) {
		if (buffer[0]=='R') {
			this->id = (int)buffer[1];
			return;
		}
		char frame[4] = {buffer[0],buffer[1] ,buffer[2] ,buffer[3] };
		this->farme‌Queue->enqueue(frame);
		});
	const char* buffer = "R";
	this->client->sendBuffer(buffer);
	while (this->id == 0) {
		std::this_thread::sleep_for(std::chrono::microseconds(10));
	}
}
void NetSnake::doNetEvent() {
	while (this->farme‌Queue->isEmpty()) {
		std::this_thread::sleep_for(std::chrono::microseconds(10));
	}
	char* frame = this->farme‌Queue->dequeue();
	qDebug() << "doNetEvent:" << frame[0] <<frame[1] << frame[2] << frame[3];
	char currentFrame;
	if (id!=frame[0]) {
		currentFrame = frame[1];
	}
	else {
		currentFrame = frame[3];
	}
	QSet<Player*>::const_iterator i;
	for (i = this->otherSnakes->constBegin(); i != this->otherSnakes->constEnd(); ++i) {
		Player* other = (*i);

		Direction value = LEFT;
		switch (currentFrame) {
		case 1:
			value = UP;
			break;
		case 2:
			value = DOWN;
			break;
		case 4:
			value = LEFT;
			break;
		case 8:
			value = RIGHT;
			break;
		}
		other->newDirect = value;
		switch (other->newDirect) {
		case UP:
			if (other->direct != DOWN) {
				other->direct = UP;
			}
			break;
		case DOWN:
			if (other->direct != UP) {
				other->direct = DOWN;
			}
			break;
		case LEFT:
			if (other->direct != RIGHT) {
				other->direct = LEFT;
			}
			break;
		case RIGHT:
			if (other->direct != LEFT) {
				other->direct = RIGHT;
			}
			break;
		}

	}
	
}


void NetSnake::loopGame() {
	doKeyEvent();
	doNetEvent();
	doGameLogic();
	renderGameFrame();
}
void NetSnake::doKeyEvent() {
	switch (newDirect) {
	case UP:
		if (direct != DOWN) {
			direct = UP;
		}
		break;
	case DOWN:
		if (direct != UP) {
			direct = DOWN;
		}
		break;
	case LEFT:
		if (direct != RIGHT) {
			direct = LEFT;
		}
		break;
	case RIGHT:
		if (direct != LEFT) {
			direct = RIGHT;
		}
		break;
	}
	int value = 1;
	switch (direct) {
	case UP:
		value = 1;
		break;
	case DOWN:
		value = 2;
		break;
	case LEFT:
		value = 4;
		break;
	case RIGHT:
		value = 8;
		break;
	}
	char buffer[1024] = { 1,'\0' };
	buffer[0] = value;
	qDebug() << "send:" << buffer;
	this->client->sendBuffer(buffer);
}

void NetSnake::updateOtherPlayers() {
	QSet<Player*>::const_iterator i;
	Player* other;
	for (i = this->otherSnakes->constBegin(); i != this->otherSnakes->constEnd(); ++i) {
		other = (*i);
		QQueue<QPoint>* currentSnake = other->player;
		QPoint delPoint;
		QPoint snakeHead = currentSnake->last();
		int newCellX = snakeHead.x();
		int newCellY = snakeHead.y();

		switch (other->direct) {
		case UP:
			newCellY -= 1;
			break;
		case DOWN:
			newCellY += 1;
			break;
		case LEFT:
			newCellX -= 1;
			break;
		case RIGHT:
			newCellX += 1;
			break;
		}

		switch (board[newCellX][newCellY]) {
		case SNAKEBODY:
			overGame();
			break;
		case NOTHING:
			currentSnake->enqueue(QPoint(newCellX, newCellY));
			delPoint = currentSnake->dequeue();
			board[snakeHead.x()][snakeHead.y()] = SNAKEBODY;
			board[newCellX][newCellY] = SNAKEHEAD;
			board[delPoint.x()][delPoint.y()] = NOTHING;
			break;
		case FOOD:
			currentSnake->enqueue(QPoint(newCellX, newCellY));
			board[snakeHead.x()][snakeHead.y()] = SNAKEBODY;
			board[newCellX][newCellY] = SNAKEHEAD;
			generateFood();
			break;
		case WALL:
			overGame();
			break;

		}
	}

}

void NetSnake::keyEvent(QKeyEvent* event) {
	QSet<Player*>::const_iterator i;
	Player* other;
	for (i = this->otherSnakes->constBegin(); i != this->otherSnakes->constEnd(); ++i) {
		other = (*i);
	}
	switch (event->key()) {
	case Qt::Key_Up:
		newDirect = UP;
		break;
	case Qt::Key_Down:
		newDirect = DOWN;
		break;
	case Qt::Key_Left:
		newDirect = LEFT;
		break;
	case Qt::Key_Right:
		newDirect = RIGHT;
		break;
	}
}

void NetSnake::initCurrentPlayer() {
	this->initPlayerPosition(this->id, NULL, true);
}

void NetSnake::initPlayerPosition(int i, Player* player, bool isCurrent) {
	if (isCurrent) {
		switch( i) {
		case 1:
			direct = newDirect = RIGHT;
			snake.clear();
			snake.enqueue(QPoint(1, cellNumY / 2));
			snake.enqueue(QPoint(2, cellNumY / 2));
			snake.enqueue(QPoint(3, cellNumY / 2));
			board[1][cellNumY / 2] = SNAKEBODY;
			board[2][cellNumY / 2] = SNAKEBODY;
			board[3][cellNumY / 2] = SNAKEHEAD;
			break;
		case 2:
			direct = newDirect = LEFT;
			snake.clear();
			snake.enqueue(QPoint(cellNumX - 1 - 1, cellNumY / 2));
			snake.enqueue(QPoint(cellNumX - 2 - 1, cellNumY / 2));
			snake.enqueue(QPoint(cellNumX - 3 - 1, cellNumY / 2));
			board[cellNumX - 1 - 1][cellNumY / 2] = SNAKEBODY;
			board[cellNumX - 2 - 1][cellNumY / 2] = SNAKEBODY;
			board[cellNumX - 3 - 1][cellNumY / 2] = SNAKEHEAD;
			break;
		}
	}
	else {
		switch (i) {
		case 1:
			player->direct = LEFT;
			player->newDirect = LEFT;
			player->player->clear();
			player->player->enqueue(QPoint(cellNumX - 1 - 1, cellNumY / 2));
			player->player->enqueue(QPoint(cellNumX - 2 - 1, cellNumY / 2));
			player->player->enqueue(QPoint(cellNumX - 3 - 1, cellNumY / 2));
			board[cellNumX - 1 - 1][cellNumY / 2] = SNAKEBODY;
			board[cellNumX - 2 - 1][cellNumY / 2] = SNAKEBODY;
			board[cellNumX - 3 - 1][cellNumY / 2] = SNAKEHEAD;
			this->otherSnakes->insert(player);
			break;
		case 2:
			player->direct = RIGHT;
			player->newDirect = RIGHT;
			player->player->clear();
			player->player->enqueue(QPoint(1, cellNumY / 2));
			player->player->enqueue(QPoint(2, cellNumY / 2));
			player->player->enqueue(QPoint(3, cellNumY / 2));
			board[1][cellNumY / 2] = SNAKEBODY;
			board[2][cellNumY / 2] = SNAKEBODY;
			board[3][cellNumY / 2] = SNAKEHEAD;
			this->otherSnakes->insert(player);
			break;
		}
	}
}


void NetSnake::initOtherPlayers() {
	this->initPlayerPosition(this->id, new Player(),false);
}




